home *** CD-ROM | disk | FTP | other *** search
/ Nautilus 1992 July / Nautilus-3-8 / Nautilus-3-8.bin / Tools & Utilities / Techy Stuff / Development Environments ƒ / Perl 4.0.2 ƒ / macperl.mus < prev    next >
Encoding:
Text File  |  1992-01-18  |  14.5 KB  |  734 lines

  1. /*********************************************************************
  2. File    :    macperl.mus    - Mac specific extensions
  3. Author    :    Tim Endres & Matthias Neeracher
  4. Started    :    28May91                                Language    :    MPW C
  5. Last    :    27Dec91
  6.  
  7. Copyright (c) 1991, 1992 Tim Endres & Matthias Neeracher
  8. *********************************************************************/
  9.  
  10. #include <Types.h>
  11. #include <QuickDraw.h>
  12. #include <Fonts.h>
  13. #include <Menus.h>
  14. #include <TextEdit.h>
  15. #include <Dialogs.h>
  16. #include <SegLoad.h>
  17. #include <StandardFile.h>
  18. #include <Lists.h>
  19. #include <Files.h>
  20.  
  21. /* Ugly hack since QuickDraw defines another invert */
  22. #define RESOLVE_MAC_CONFLICTS
  23.  
  24. #include "EXTERN.h"
  25. #include "perl.h"
  26.  
  27. extern int wantarray;
  28.  
  29. char *savestr();
  30.  
  31. static enum macvars {
  32.     UV_macerr,
  33. };
  34.  
  35. static enum macsubs {
  36.     US_mac_sfgetfile,
  37.     US_mac_sfgetfolder,
  38.     US_mac_sfputfile,
  39.     US_mac_answer,
  40.     US_mac_ask,
  41.     US_mac_pick,
  42. };
  43.  
  44. static int macsub();
  45. static int macset();
  46. static int macval();
  47.  
  48. static int    _mac_error_ = 0;
  49.  
  50. void InitToolbox()
  51. {
  52.     InitGraf((Ptr) &qd.thePort);
  53.     InitFonts();
  54.     InitWindows();
  55.     InitMenus();
  56.     TEInit();
  57.     InitDialogs(nil);
  58.     InitCursor();
  59. }
  60.  
  61. int
  62. init_macintosh()
  63. {
  64.     struct ufuncs uf;
  65.     char *filename = "macperl.c";
  66.  
  67.     uf.uf_set = macset;
  68.     uf.uf_val = macval;
  69.  
  70. #define MAGICVAR(name, ix) uf.uf_index = ix, magicname(name, &uf, sizeof uf)
  71.  
  72.     MAGICVAR("macerr",        UV_macerr);
  73.  
  74.     make_usub("sfgetfile",    US_mac_sfgetfile,    macsub, filename);
  75.     make_usub("sfgetfolder",US_mac_sfgetfolder,    macsub, filename);
  76.     make_usub("sfputfile",    US_mac_sfputfile,    macsub, filename);
  77.     make_usub("answer",        US_mac_answer,        macsub, filename);
  78.     make_usub("ask",        US_mac_ask,            macsub, filename);
  79.     make_usub("pick",        US_mac_pick,        macsub, filename);
  80.     
  81.     return 1;
  82. };
  83.  
  84. static void CenterWindow(DialogPtr dlg)
  85. {
  86.     Rect    *        screen;
  87.     short            hPos;
  88.     short            vPos;
  89.     
  90.     screen    =    &qd.screenBits.bounds;
  91.     hPos    =    screen->right+screen->left-dlg->portRect.right >> 1;
  92.     vPos    =    (screen->bottom-screen->top-dlg->portRect.bottom)/3;
  93.     vPos    +=    screen->top;
  94.     MoveWindow(dlg, hPos, vPos, true);
  95. }    
  96.  
  97. static ControlHandle GetDlgCtrl(DialogPtr dlg, short item)
  98. {
  99.     short     kind;
  100.     Handle    hdl;
  101.     Rect    box;
  102.     
  103.     GetDItem(dlg, item, &kind, &hdl, &box);
  104.     return (ControlHandle) hdl;
  105. }
  106.  
  107. static void GetDlgText(DialogPtr dlg, short item, char * text)
  108. {
  109.     getitext((Handle) GetDlgCtrl(dlg, item), text);
  110. }
  111.  
  112. static void SetDlgText(DialogPtr dlg, short item, char * text)
  113. {
  114.     setitext((Handle) GetDlgCtrl(dlg, item), text);
  115. }
  116.  
  117. static void GetDlgRect(DialogPtr dlg, short item, Rect * r)
  118. {
  119.     short     kind;
  120.     Handle    hdl;
  121.     
  122.     GetDItem(dlg, item, &kind, &hdl, r);
  123. }
  124.  
  125. static void FrameDlgRect(DialogPtr dlg, short item)
  126. {
  127.     Rect    r;
  128.     
  129.     GetDlgRect(dlg, item, &r);
  130.     InsetRect(&r, -4, -4);
  131.     PenSize(3, 3);
  132.     FrameRoundRect(&r, 16, 16);
  133.     PenSize(1,1);
  134. }
  135.  
  136. static int
  137. macsub(ix, sp, items)
  138. int    ix;
  139. int sp;
  140. int items;
  141. {
  142.     STR **st = stack->ary_array + sp;
  143.     STR *Str;        /* used in str_get and str_gnum macros */
  144.  
  145.     switch (ix)    {
  146.     case US_mac_sfgetfile:
  147.         if (items < 4 || items > 5)
  148.             fatal("Usage: &sfgetfile($h, $v, $filetypes, $filename [, $defaultpath])");
  149.         else {
  150.             int        retval;
  151.             int        h            =    (int)    str_gnum(st[1]);
  152.             int        v            =    (int)    str_gnum(st[2]);
  153.             char*    filetypes     =    (char*)    str_get(st[3]);
  154.             char*    filename;
  155.             char*    defaultpath;
  156.             
  157.             if (items < 5)
  158.                 defaultpath    =    "";
  159.             else
  160.                 defaultpath    =    (char*)        str_get(st[5]);
  161.                 
  162.             retval = mac_sfgetfile(h, v, defaultpath, filetypes, &filename);
  163.             str_numset(st[0], (double) retval);
  164.             str_set(st[4], (char*) filename);
  165.         }
  166.         return sp;
  167.  
  168.     case US_mac_sfgetfolder:
  169.         if (items < 3 || items > 4)
  170.             fatal("Usage: &sfgetfolder($h, $v, $foldername [, $defaultpath])");
  171.         else {
  172.             int        retval;
  173.             int        h            =    (int)    str_gnum(st[1]);
  174.             int        v            =    (int)    str_gnum(st[2]);
  175.             char*    filename;
  176.             char*    defaultpath;
  177.             
  178.             if (items < 4)
  179.                 defaultpath    =    "";
  180.             else
  181.                 defaultpath    =    (char*)        str_get(st[4]);
  182.                 
  183.             retval = mac_sfgetfolder(h, v, defaultpath, &filename);
  184.             str_numset(st[0], (double) retval);
  185.             str_set(st[3], (char*) filename);
  186.         }
  187.         return sp;
  188.  
  189.     case US_mac_sfputfile:
  190.         if (items < 4 || items > 6)
  191.             fatal("Usage: &sfputfile($h, $v, $prompt, $filename [, $defaultname] [, $defaultpath])");
  192.         else {
  193.             int        retval;
  194.             int        h            =    (int)    str_gnum(st[1]);
  195.             int        v            =    (int)    str_gnum(st[2]);
  196.             char*    prompt        =    (char*)    str_get(st[3]);
  197.             char*    filename;
  198.             char*    defaultname;
  199.             char*    defaultpath;
  200.             
  201.             if (items < 6)
  202.                 defaultpath    =    "";
  203.             else
  204.                 defaultpath    =    (char*)        str_get(st[6]);
  205.  
  206.             if (items < 5)
  207.                 defaultname    =    "Untitled";
  208.             else
  209.                 defaultname    =    (char*)        str_get(st[5]);
  210.                 
  211.             retval = mac_sfputfile(h, v, prompt, defaultpath, defaultname, &filename);
  212.             str_numset(st[0], (double) retval);
  213.             str_set(st[4], (char*) filename);
  214.         }
  215.         return sp;
  216.  
  217.     case US_mac_ask:
  218.         if (items < 2 || items > 3)
  219.             fatal("Usage: &ask($prompt, $string [, $defaultstr])");
  220.         else {
  221.             int retval;
  222.             char*    prompt     =    (char*)        str_get(st[1]);
  223.             char*    string;
  224.             char*    defaultstr;
  225.     
  226.             if (items < 3)
  227.                 defaultstr = "";
  228.             else 
  229.                 defaultstr    = (char*) str_get(st[3]);
  230.                 
  231.             retval = mac_ask(prompt, defaultstr, &string);
  232.             str_numset(st[0], (double) retval);
  233.             str_set(st[2], (char*) string);
  234.         }
  235.         return sp;
  236.  
  237.     case US_mac_answer:
  238.         if (items < 1 ||╩items > 4)
  239.             fatal("Usage: &answer($prompt [, $button1] [, $button2] [, $button3] )");
  240.         else {
  241.             int     retval;
  242.             int        i;
  243.             char*   prompt    =    (char*)        str_get(st[1]);
  244.             char*    buttons[3];
  245.             
  246.             for (i=1; i++<items;)
  247.                 buttons[i-2]    = str_get(st[i]);    
  248.             
  249.             if (items == 1)    {
  250.                 buttons[0]    =    "OK";
  251.                 items        =    2;
  252.             }
  253.                 
  254.             retval = mac_answer(prompt, items-1, buttons);
  255.             str_numset(st[0], (double) retval);
  256.         }
  257.         return sp;
  258.  
  259.     case US_mac_pick:
  260.         if (items < 3)
  261.             fatal("Usage: &pick($prompt, $choice╔, $pick)");
  262.         else {
  263.             int     retval;
  264.             char*    prompt         =    (char*)        str_get(st[1]);
  265.             char*    pick;
  266.     
  267.             retval = mac_list_pick(prompt, st+2, items-2, &pick);
  268.             str_numset(st[0], (double) retval);
  269.             str_set(st[items], (char*) pick);
  270.         }
  271.         return sp;
  272.  
  273.     default:
  274.         fatal("Unimplemented user-defined subroutine");
  275.         break;
  276.     }
  277.     
  278.     return sp;
  279. }
  280.  
  281. static int
  282. macval(ix, str)
  283. int ix;
  284. STR *str;
  285. {
  286.     switch (ix) {
  287.         case UV_macerr:
  288.             str_numset(str, (double)_mac_error_);
  289.             break;
  290.         }
  291.     return 0;
  292. }
  293.  
  294. static int
  295. macset(ix, str)
  296. int ix;
  297. STR *str;
  298. {
  299.     switch (ix) {
  300.         case UV_macerr:
  301.             _mac_error_ = (int)str_gnum(str);
  302.             break;
  303.         }
  304.     return 0;
  305. }
  306.  
  307. #define TempPStr(cstr)    ((StringPtr) memcpy(tmpPStr+1, cstr, *tmpPStr = strlen(cstr)), tmpPStr)
  308.  
  309. int
  310. mac_answer(prompt, butCnt, buttons)
  311.     char *    prompt;
  312.     int        butCnt;
  313.     char **    buttons;
  314. {
  315.     short        item;
  316.     DialogPtr    mydialog;
  317.     Str255        tmpPStr;
  318.  
  319.     mydialog = GetNewDialog(2000+butCnt, NULL, (WindowPtr)-1);
  320.     if (mydialog == NULL)
  321.         return 0;
  322.     
  323.     InitCursor();
  324.     SetDlgText(mydialog, 5, prompt);
  325.     
  326.     for (item = 0; item<butCnt; item++)
  327.         SetCTitle(GetDlgCtrl(mydialog, item+1), TempPStr(buttons[item]));
  328.     
  329.     CenterWindow(mydialog);
  330.     ShowWindow(mydialog);
  331.     SetPort(mydialog);
  332.     FrameDlgRect(mydialog, ok);
  333.     ModalDialog((ModalFilterProcPtr)0, &item);
  334.     DisposDialog(mydialog);
  335.     
  336.     return butCnt-item;
  337. }
  338.  
  339. static char     string_reply[256];
  340.  
  341. int
  342. mac_ask(prompt, defaultstr, string)
  343.     char *    prompt;
  344.     char *     defaultstr;
  345.     char **    string;
  346. {
  347.     short        item;
  348.     DialogPtr    mydialog;
  349.  
  350.     mydialog = GetNewDialog((short)2010, NULL, (WindowPtr)-1);
  351.     if (mydialog == NULL)
  352.         return 0;
  353.     
  354.     SetDlgText(mydialog, 3, prompt);
  355.     if (*defaultstr)
  356.         SetDlgText(mydialog, 4, defaultstr);
  357.     SelIText(mydialog, 4, 0, 1024);
  358.  
  359.     InitCursor();
  360.     CenterWindow(mydialog);
  361.     ShowWindow(mydialog);
  362.     SetPort(mydialog);
  363.     FrameDlgRect(mydialog, ok);
  364.     ModalDialog((ModalFilterProcPtr)0, &item);
  365.     switch (item) {
  366.     case ok:
  367.         GetDlgText(mydialog, 4, string_reply);
  368.         *string = string_reply;
  369.         break;
  370.     case cancel:
  371.         break;
  372.     }
  373.     DisposDialog(mydialog);
  374.     
  375.     return 2-item;
  376. }
  377.  
  378. #define SFSaveDisk        (* (short *) 0x0214)
  379. #define CurDirStore        (* (long *)  0x0398)
  380.  
  381. int
  382. mac_sfgetfile(h, v, defaultpath, filetypes, filepath)
  383.     int        h, v;
  384.     char    *defaultpath;
  385.     char    *filetypes;
  386.     char    **filepath;
  387. {
  388.     int                i, length, num_types = -1;
  389.     long            savedir;
  390.     short            savedisk;
  391.     char            *ptr;
  392.     Point            mypoint;
  393.     SFTypeList        mytypes;
  394.     SFReply            myreply;
  395.     FSSpec            desc;
  396.  
  397.     mypoint.h = h;
  398.     mypoint.v = v;
  399.     length = strlen(filetypes);
  400.     for (i=0,ptr=filetypes ; length >= 4 && i < 4 ; length -= 4, i++, ptr+=4) {
  401.         strncpy((char *)&mytypes[i], ptr, 4);
  402.         num_types += (num_types == -1) ? 2 : 1;
  403.         }
  404.     
  405.     if (*defaultpath) {
  406.         savedisk = SFSaveDisk;
  407.         savedir = CurDirStore;
  408.         if (!Path2FSSpec(defaultpath, &desc) && !FSpDown(&desc, ""))    {
  409.             SFSaveDisk     = -desc.vRefNum;
  410.             CurDirStore = desc.parID;
  411.         }
  412.     }
  413.     
  414.     SFGetFile(mypoint, "\p", NULL, num_types, mytypes, NULL, &myreply);
  415.     if (myreply.good) {
  416.         WD2FSSpec(myreply.vRefNum, myreply.fName, &desc);
  417.         *filepath = FSp2FullPath(&desc);
  418.     }
  419.     
  420.     if (*defaultpath) {
  421.         SFSaveDisk = savedisk;
  422.         CurDirStore = savedir;
  423.     }
  424.     
  425.     return myreply.good;
  426. }
  427.  
  428. static long     currentDir;
  429. static SFReply    reply;
  430.  
  431. static pascal Boolean FolderFFilter(ParmBlkPtr p)
  432. {
  433.     return !(p->fileParam.ioFlAttrib & ioDirMask);
  434. }
  435.  
  436. static pascal short GetDirDlgHook(short item, DialogPtr dlgPtr)
  437. {
  438.     switch (item) {
  439.     case 11:
  440.         if (reply.fType) {
  441.             currentDir    =    reply.fType;
  442.             return    1;
  443.         }
  444.         break;
  445.     
  446.     case 12:
  447.         currentDir    =    CurDirStore;
  448.         
  449.         return 1;
  450.     case 100:
  451.         if (!reply.fType)
  452.             HiliteControl(GetDlgCtrl(dlgPtr, 11), 255);
  453.         else
  454.             HiliteControl(GetDlgCtrl(dlgPtr, 11), 0);
  455.         break;
  456.     }
  457.     
  458.     return item;
  459. }
  460.  
  461. int
  462. mac_sfgetfolder(h, v, defaultpath, filepath)
  463.     int        h, v;
  464.     char    *defaultpath;
  465.     char    **filepath;
  466. {
  467.     long        savedir;
  468.     short        savedisk;
  469.     Point        mypoint;
  470.     FSSpec        desc;
  471.  
  472.     mypoint.h = h;
  473.     mypoint.v = v;
  474.     
  475.     if (*defaultpath) {
  476.         savedisk = SFSaveDisk;
  477.         savedir = CurDirStore;
  478.         if (!Path2FSSpec(defaultpath, &desc) && !FSpDown(&desc, ""))    {
  479.             SFSaveDisk     = -desc.vRefNum;
  480.             CurDirStore = desc.parID;
  481.         }
  482.     }
  483.     
  484.     SFPGetFile(
  485.         mypoint, 
  486.         '', 
  487.         FolderFFilter, 
  488.         -1, 
  489.         nil, 
  490.         GetDirDlgHook, 
  491.         &reply,
  492.         2030,                
  493.         nil);
  494.  
  495.     if (reply.good) {
  496.         desc.vRefNum    =    -SFSaveDisk;
  497.         desc.parID        =    currentDir;
  498.         if (FSpUp(&desc))
  499.             return false;
  500.         *filepath = FSp2FullPath(&desc);
  501.     }
  502.     
  503.     if (*defaultpath) {
  504.         SFSaveDisk = savedisk;
  505.         CurDirStore = savedir;
  506.     }
  507.     
  508.     return reply.good;
  509. }
  510.  
  511. int
  512. mac_sfputfile(h, v, prompt, defaultpath, defaultname, filepath)
  513.     int        h, v;
  514.     char    *prompt;
  515.     char    *defaultpath;
  516.     char    *defaultname;
  517.     char    **filepath;
  518. {
  519.     long            savedir;
  520.     short            savedisk;
  521.     Point            mypoint;
  522.     SFReply            myreply;
  523.     FSSpec            desc;
  524.  
  525.     mypoint.h = h;
  526.     mypoint.v = v;
  527.     
  528.     if (*defaultpath) {
  529.         savedisk = SFSaveDisk;
  530.         savedir = CurDirStore;
  531.         if (!Path2FSSpec(defaultpath, &desc) && !FSpDown(&desc, ""))    {
  532.             SFSaveDisk     = -desc.vRefNum;
  533.             CurDirStore = desc.parID;
  534.         }
  535.     }
  536.     
  537.     sfputfile(&mypoint, prompt, defaultname, NULL, &myreply);
  538.     if (myreply.good) {
  539.         WD2FSSpec(myreply.vRefNum, myreply.fName, &desc);
  540.         *filepath = FSp2FullPath(&desc);
  541.     }
  542.     
  543.     if (*defaultpath) {
  544.         SFSaveDisk = savedisk;
  545.         CurDirStore = savedir;
  546.     }
  547.     
  548.     return myreply.good;
  549. }
  550.  
  551. static ListHandle picklist = NULL;
  552.  
  553. #define SetCell(cell, row, column)    { (cell).h = column; (cell).v = row; }
  554. #define ROW(cell)                     (cell).v
  555.  
  556. pascal void
  557. MacListUpdate(myDialog, myItem)
  558. DialogPtr        myDialog;
  559. short            myItem;
  560. {
  561. Rect            myrect;
  562. #pragma unused (myItem)
  563.  
  564.     LUpdate(myDialog->visRgn, picklist);
  565.     myrect = (**(picklist)).rView;
  566.     InsetRect(&myrect, -1, -1);
  567.     FrameRect(&myrect);
  568.     }
  569.  
  570. pascal Boolean
  571. MacListFilter(myDialog, myEvent, myItem)
  572. DialogPtr        myDialog;
  573. EventRecord        *myEvent;
  574. short            *myItem;
  575. {
  576. Rect    listrect;
  577. short    myascii;
  578. Handle    myhandle;
  579. Point    mypoint;
  580. short    mytype;
  581. int        activate;
  582.  
  583.     SetPort(myDialog);
  584.     if (myEvent->what == keyDown) {
  585.         myascii = myEvent->message % 256;
  586.         if (myascii == '\015' || myascii == '\003') {    /* This is return or enter... */
  587.             *myItem = 1;
  588.             return true;
  589.             }
  590.         }
  591.     else if (myEvent->what == mouseDown) {
  592.         mypoint = myEvent->where;
  593.         GlobalToLocal(&mypoint);
  594.         GetDItem(myDialog, 4, &mytype, &myhandle, &listrect);
  595.         if (PtInRect(mypoint, &listrect) && picklist != NULL) {
  596.             if (LClick(mypoint, (short)myEvent->modifiers, picklist)) {
  597.                 /* User double-clicked in cell... */
  598.                 *myItem = 1;
  599.                 return true;
  600.                 }
  601.             }
  602.         }
  603.     else if (myEvent->what == activateEvt && picklist != NULL) {
  604.         activate = (myEvent->modifiers & 0x01) != 0;
  605.         LActivate((Boolean) activate, picklist);
  606.         }
  607.     
  608.     return false;
  609.     }
  610.  
  611. mac_list_pick(prompt, list_string, count, pick)
  612. char    *prompt;
  613. STR **    list_string;
  614. int        count;
  615. char    **pick;
  616. {
  617.     short        itemHit, length;
  618.     Boolean        done;
  619.     DialogPtr    mydialog;
  620.     ListHandle    mylist;
  621.     Cell        mycell;
  622.     short        mytype;
  623.     Handle        myhandle;
  624.     Point        cellsize;
  625.     Rect        listrect, dbounds;
  626.     char    *    item;
  627.  
  628.     InitCursor();
  629.     mydialog = GetNewDialog(2020, NULL, (WindowPtr)-1);
  630.     if (!mydialog)
  631.         return 0;
  632.     
  633.     SetDlgText(mydialog, 3, prompt);
  634.     GetDItem(mydialog, 4, &mytype, &myhandle, &listrect);
  635.     SetDItem(mydialog, 4, mytype, (Handle)MacListUpdate, &listrect);
  636.     
  637.     SetPort(mydialog);
  638.     InsetRect(&listrect, 1, 1);
  639.     SetRect(&dbounds, 0, 0, 1, count);
  640.     cellsize.h = (listrect.right - listrect.left);
  641.     cellsize.v = 17;
  642.  
  643.     listrect.right -= 15;
  644.  
  645.     picklist = LNew(&listrect, &dbounds, cellsize, 0,
  646.                             mydialog, true, false, false, true);
  647.  
  648.     mylist = picklist;
  649.     LDoDraw(false, mylist);
  650.     
  651.     SetCell(mycell, 0, 0);
  652.     for (; mycell.v <count; ++mycell.v)    {
  653.         item = str_get(list_string[mycell.v]);
  654.         LSetCell(item, strlen(item), mycell, mylist);
  655.     }
  656.  
  657.     LDoDraw(true, mylist);
  658.     CenterWindow(mydialog);
  659.     ShowWindow(mydialog);
  660.     
  661.     for (done=false; !done; )    {
  662.         SetPort(mydialog);
  663.         FrameDlgRect(mydialog, ok);
  664.         ModalDialog(MacListFilter, &itemHit);
  665.         switch (itemHit) {
  666.         case ok:
  667.             SetCell(mycell, 0, 0);
  668.             done = true;
  669.             if (LGetSelect(true, &mycell, picklist)) {
  670.                 length = 255;
  671.                 LGetCell(string_reply, &length, mycell, picklist);
  672.                 string_reply[length] = '\0';
  673.                 *pick = string_reply;
  674.                 break;
  675.             } else
  676.                 itemHit = cancel;
  677.             break;
  678.         case cancel:
  679.             done = true;
  680.             break;
  681.         }
  682.  
  683.         }    /* Modal Loop */
  684.         
  685.     SetPort(mydialog);
  686.     
  687.     LDispose(mylist);
  688.     picklist = NULL;
  689.     DisposDialog(mydialog);
  690.     
  691.     return (itemHit == ok);
  692. }
  693.  
  694. void SpinPerlCursor(int direction)
  695. {
  696.     static int delay = 0;
  697.     
  698.     if (!(delay++ % 10))
  699.         SpinCursor(direction);
  700. }
  701.  
  702. void GetProgFile(FSSpec * desc)
  703. {
  704.     short    message;
  705.     short    count;
  706.  
  707.     CountAppFiles(&message, &count);
  708.     
  709.     if (count) {
  710.         AppFile    arg;
  711.         
  712.         GetAppFiles(1, &arg);
  713.     
  714.         if (arg.fType != 'TEXT')
  715.             fatal("MacPerl can't do anything with a non-text file.\n");
  716.     
  717.         WD2FSSpec(arg.vRefNum, arg.fName, desc);
  718.     } else {
  719.         Point     wh;
  720.         SFTypeList    types;
  721.         SFReply    reply;
  722.         
  723.         wh.h = wh.v = 75;
  724.         types[0]    = 'TEXT';
  725.         
  726.         SFGetFile(wh, "", (FileFilterProcPtr) nil, 1, types, (DlgHookProcPtr) nil, &reply);
  727.  
  728.         if (!reply.good)
  729.             fatal("MacPerl needs a program file to run.\n");
  730.     
  731.         WD2FSSpec(reply.vRefNum, reply.fName, desc);
  732.     }
  733. }
  734.